package com.uam.core.scheduler;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.uam.core.business.TimeToPointIndex;
import com.uam.core.cache.PointCacheConfig;
import com.uam.core.dao.mysql.TaskDao;
import com.uam.core.entity.PointInfoData;
import com.uam.core.entity.constant.RedisConstants;
import com.uam.core.entity.model.RedisAltitudeInfo;
import com.uam.core.entity.model.entity.uitls.SpatialUtil;
import com.uam.core.lk.utils.GeoTools;
import com.uam.core.lk.utils.RegionUtil;
import com.uam.core.lk.utils.fencebuffer.BufferBase;
import com.uam.core.service.SectorService;
import com.uam.core.tool.DateUtils;
import com.uam.core.websocket.WebSocketServer;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;

/**
 * 实时点消费
 */
@Component
@Slf4j
public class RelPointScheduler {

    @Autowired
    private ConflictResolution conflictResolution;
    @Autowired
    private PointCacheConfig pointCacheConfig;

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private WebSocketServer socketServer;

    @Autowired
    private TaskDao taskDao;

    @Autowired
    private SectorService sectorService;


//    @Scheduled(fixedDelay = 1000L)
//    public void sectorStatDel() {
//        String key = DateUtils.format(System.currentTimeMillis());
//        Set<Integer> takIds= pointCacheConfig.getAll().asMap().keySet();
//        for (Integer takId : takIds) {
//            Map<String, PointInfoData> dataMap = pointCacheConfig.get(takId);
//            if (dataMap == null) {
//                continue;
//            }
//            dataMap.remove(key);
//            if(dataMap.size() <=2){
//                pointCacheConfig.del(takId);
//            }
//        }
//    }

//    RedisConstants.TASK_MODEL_INFO+taskModel.getId()
    @Scheduled(fixedDelay = 3000L)
    public void sectorStat() {

        Map<Integer, Map<String, PointInfoData>> integerMapMap = pointCacheConfig.getAll().asMap();
        Set<Integer> takIds = pointCacheConfig.getAll().asMap().keySet();
        for (Integer takId : takIds) {
            try {
                long nowTime = System.currentTimeMillis();
                //当前任务
                Map<String, PointInfoData> dataMap = pointCacheConfig.get(takId);
                if (dataMap == null || dataMap.size() == 0) {
                    continue;
                }

                List<PointInfoData> pointInfoData = new ArrayList<>(dataMap.values());
                int row = pointInfoData.size();

                PointInfoData endTimeData = pointInfoData.get(row - 1);

                if (nowTime > endTimeData.getTime()) {
                    del(takId,pointInfoData);
                    continue;
                }


                PointInfoData pointInfoData1 = TimeToPointIndex.newPointData(pointInfoData, nowTime,takId);



                if (pointInfoData1 != null) {
                    //广播基站信息
                    socketServer.broadCastInfo(pointInfoData1, takId);
                    //判断是不是对冲，路线相同
                    List<PointInfoData> tempList = null;
                    try {
                        tempList = pointInfoData.subList(pointInfoData1.getIndex(), row - 2);
                    } catch (Exception e) {
                        continue;
                    }
                    solveConflict(integerMapMap, pointInfoData1, takId, tempList, pointInfoData);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    public static boolean areSegmentsInSameDirection(Coordinate p1, Coordinate p2, Coordinate q1, Coordinate q2) {
        // 向量 P1P2
        double dx1 = p2.getX()- p1.getX();
        double dy1 = p2.getY() - p1.getY();

        // 向量 Q1Q2
        double dx2 = q2.getX()- q1.getX();
        double dy2 = q2.getY() - q1.getY();
        // 检查向量是否平行，即两个向量的叉积是否为零
        System.out.println((dx1 * dy2 - dx2 * dy1));
            return (dx1 * dy2 - dx2 * dy1) <=0;
    }

    public void solveConflict(Map<Integer, Map<String, PointInfoData>> mapMap, PointInfoData newPoint, Integer takId, List<PointInfoData> sourcePointInfoData, List<PointInfoData> allPoint) throws IOException {

        PointInfoDo pointInfoDo = PointInfoScheduler.getPointInfoDo(takId);
        if (pointInfoDo == null) {
            PointInfoScheduler.setPointInfoDo(takId,new PointInfoDo(takId,newPoint.getEndTime()));
            pointInfoDo = PointInfoScheduler.getPointInfoDo(takId);
        }

        for (Map.Entry<Integer, Map<String, PointInfoData>> entry : mapMap.entrySet()) {
            Integer k = entry.getKey();
            Map<String, PointInfoData> v = entry.getValue();
            if (k.equals(takId)) {
                continue;
            }

            List<PointInfoData> pointInfoData = new ArrayList<>(v.values());
            PointInfoData pointInfoData1 = TimeToPointIndex.newPointData(pointInfoData, System.currentTimeMillis(),k);
            if (pointInfoData1 == null) {
               continue;
            }


            CollisionDo collisionDo = pointInfoDo.getCollisionDo(k);
            if (collisionDo == null) {
                solve(takId, sourcePointInfoData, allPoint, pointInfoData1, k, newPoint);
                collisionDo = pointInfoDo.getCollisionDo(k);
            }

            //没有碰突
            if(collisionDo == null){
                continue;
            }
            //已经处理
            if (collisionDo.getStatus() == 1) {
                continue;
            }

            //如果两个飞机速度相同，方向相同可以不避让
            if (newPoint.getSpeed() == pointInfoData1.getSpeed() ) {
                try {
                    if(pointInfoData1.getIndex() <3 || newPoint.getBuffer()<3){
                        continue;
                    }
                    PointInfoData a = allPoint.get(newPoint.getIndex() + 2);
                    PointInfoData b = pointInfoData.get(pointInfoData1.getIndex() + 2);

                    PointInfoData s1= allPoint.get(0);
                    PointInfoData s2= allPoint.get(allPoint.size()-1);
                    PointInfoData e1= pointInfoData.get(0);
                    PointInfoData e2=pointInfoData.get(pointInfoData.size()-1);

                     String key1= s1.getLon()+"_"+s1.getLat();
                     String key2= s2.getLon()+"_"+s2.getLat();

                    String key4= e1.getLon()+"_"+e1.getLat();
                    String key5= e2.getLon()+"_"+e2.getLat();
                    if( key1.equals(key4) && key2.equals(key5) ){
//                        System.out.println("方向和速度起点终点都相同，不做处理");
//                        collisionDo.setStatus(1);
                        continue;
                    }

//                    if (areLinesInSameDirection(new Coordinate(newPoint.getLon(), newPoint.getLat()), new Coordinate(a.getLon(), a.getLat()),
//                            new Coordinate(pointInfoData1.getLon(), pointInfoData1.getLat()), new Coordinate(b.getLon(), b.getLat()))) {
//                        System.out.println("方向和速度都相同，不做处理");
//                        collisionDo.setStatus(1);
//                        continue;
//                    }


                }catch (Exception e){
//                    e.printStackTrace();
                }
            }


            //对冲和相交是通一个办法解决
            if (collisionDo.collision == 1 || collisionDo.collision == 2) {
                double distance = SpatialUtil.computeDistance(newPoint.getLon(), newPoint.getLat(), pointInfoData1.getLon(), pointInfoData1.getLat());
                String type = collisionDo.collision == 1 ? "对冲" : "相交";
//                System.out.println(takId + "  " + k + " " + type + "----相对距离：" + distance + "  安全距离：" + newPoint.getSafeDistance()  + "  当前飞机位置" + newPoint.getIndex() + "  对冲飞机位置" + pointInfoData1.getIndex() + ",当前飞行时间：" + DateUtils.format(newPoint.getTime()) + "  对冲飞机时间" + DateUtils.format(pointInfoData1.getTime()) + ",当前轨迹数量：" + allPoint.size() + ",对冲轨迹数量：" + pointInfoData.size());
                if (distance <= newPoint.getSafeDistance() ) {
                    System.out.println("碰撞：——》"+takId + "  " + k + " " + type + "----相对距离：" + distance + "  安全距离：" + newPoint.getSafeDistance()  + "  当前飞机位置" + newPoint.getIndex() + "  对冲飞机位置" + pointInfoData1.getIndex() + ",当前飞行时间：" + DateUtils.format(newPoint.getTime()) + "  对冲飞机时间" + DateUtils.format(pointInfoData1.getTime()) + ",当前轨迹数量：" + allPoint.size() + ",对冲轨迹数量：" + pointInfoData.size());
                    conflictResolution.conflictHandling(takId, k, type, distance, newPoint, pointInfoData1, sourcePointInfoData, allPoint);
                }
            } else {
                solve(takId, sourcePointInfoData, allPoint, pointInfoData1, k, newPoint);
            }
        }
    }


    public void solveConflict(Map<Integer, Map<String, PointInfoData>> mapMap, PointInfoData newPoint, Integer takId, List<PointInfoData> one, List<PointInfoData> allPoint, PointInfoDo pointInfoDo) {
//         double  distance=   SpatialUtil.computeDistance(newPoint.getLon(), newPoint.getLat(), pointInfoData1.getLon(), pointInfoData1.getLat());
//               System.out.println("a----相对距离"+distance+ "  安全距离："+ newPoint.getSafeDistance()*6+"  当前飞机位置" + newPoint.getIndex() +"  对冲飞机位置"+pointInfoData1.getIndex() +",当前飞行时间："+ DateUtils.format(newPoint.getTime())
//                       +"  对冲飞机时间"+DateUtils.format(pointInfoData1.getTime())+",当前飞行数量："+allPoint.size()+",对冲飞机数量："+pointInfoData.size());
//               if(distance<= newPoint.getSafeDistance()*6){
//                   System.out.println("------对---冲");
//               }
    }

//    生成注释
    public static boolean areLinesInSameDirection(Coordinate start1, Coordinate end1, Coordinate start2, Coordinate end2) {
        GeometryFactory factory = new GeometryFactory();

        // 创建两条线段
        LineString line1 = factory.createLineString(new Coordinate[]{start1, end1});
        LineString line2 = factory.createLineString(new Coordinate[]{start2, end2});

        // 检查两条线段是否在同一直线上且方向相同
        // 这里我们先检查起点和终点是否分别对应
        boolean startsMatch = start1.equals2D(start2) && end1.equals2D(end2);
        boolean endsMatch = start1.equals2D(end2) && end1.equals2D(start2);

        // 如果起点和终点分别对应，再检查线段是否在拓扑上相等
        if (startsMatch || endsMatch) {
            return line1.equalsTopo(line2);
        } else {
            return false;
        }
    }
    /**
     * 判断相交 还是对冲
     *
     * @param takId
     * @param one
     * @param pointInfoData
     * @param pointInfoData1
     * @param sourceTaskId
     */
    public void solve(Integer takId, List<PointInfoData> one, List<PointInfoData> pointInfoData, PointInfoData pointInfoData1, Integer sourceTaskId, PointInfoData newPoint) {
        //判断是不是对冲
        List<PointInfoData> two=null;
        LineString stringOne=null;
        LineString stringTwo=null;
        Geometry geometry=null;
        try {
            two = pointInfoData.subList(pointInfoData1.getIndex(), pointInfoData.size() - 2);
        } catch (Exception e) {
//            del(takId);
            return;
        }
        try{
            //最后三个点已经开始降落或其飞
            if(one.size()<3 || two.size() < 3 || pointInfoData1.getIndex() <3 || newPoint.getBuffer()<3){
                return;
            }
            stringOne  = TimeToPointIndex.getLineString(one);
            stringTwo = TimeToPointIndex.getLineString(two);
            geometry = stringOne.intersection(stringTwo);
        }catch (Exception e){
            System.out.println("判断失败  "+one.size() +" "+ two.size());
            return;
        }



        CollisionDo collisionDo = new CollisionDo(sourceTaskId, 0);
        //判断是不是对冲 是
        if (geometry != null && geometry.getNumGeometries() > 3) {
            collisionDo.setCollision(1);
            PointInfoScheduler.getPointInfoDo(takId).getCllisionMap().put(sourceTaskId, collisionDo);
            return;
        }

        //如果有相交
        if (geometry != null && !geometry.isEmpty()) {
            //判断两点之间的距离是否在缓冲区内
            collisionDo.setCollision(2);
            PointInfoScheduler.getPointInfoDo(takId).getCllisionMap().put(sourceTaskId, collisionDo);
            return;
        }
        //没有相交的情况不做处理
    }

    public void del(Integer sourceTaskId,List<PointInfoData> pointInfoData ) {
        double sum = 0.0;
        int row = pointInfoData.size();

        for (int i = 0; i < row; i++) {
            PointInfoData trackPointInfo = pointInfoData.get(i);
            sum=sum+trackPointInfo.getLast_position_distance();
        }

        RedisAltitudeInfo redisAltitudeInfo= ( RedisAltitudeInfo)redisTemplate.opsForValue().get(RedisConstants.TASK_MODEL_INFO+sourceTaskId);
        double cost=(sum/(redisAltitudeInfo.getAircraftModel().getSpeed()*1000))/60;

        taskDao.completeTask(sourceTaskId,sum, cost);
        //飞行任务结束
        PointInfoScheduler.deletePointInfoDo(sourceTaskId);
        pointCacheConfig.del(sourceTaskId);
        redisTemplate.delete(RedisConstants.ROUTE_POINTS + sourceTaskId);
        redisTemplate.delete(RedisConstants.TASK_MODEL_INFO + sourceTaskId);
    }

//    public static void main(String[] args) {
//        String wtr1="LINESTRING ( 112.883999 28.287999, 112.88314186444141 28.28714186444142 )";
//        String wtr2="LINESTRING ( 112.881999 28.285999, 112.885999 28.289999 )";
//        LineString wtr1Line= getLineString(wtr1);
//        LineString wtr1Line2= getLineString(wtr2);
//        Geometry geometry = stringOne.intersection(stringTwo);
//    }

    public static LineString getLineString(String wtr) {
        WKTReader reader = new WKTReader(new GeometryFactory());
        LineString lineString=null;
        try {
            // 使用WKTReader将WKT字符串转换为LineString对象
             lineString = (LineString) reader.read(wtr);

            // 输出转换后的LineString对象
            System.out.println("Converted LineString: " + lineString);
        } catch (Exception e) {
            // 处理可能的异常，例如WKT格式错误
            e.printStackTrace();
        }
        return lineString;
    }
}
